﻿using Cms.Core.Data.Transactions;
using Cms.Core.Infrastructure.Dependency;
using Cms.Core.Infrastructure.Log;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Cms.Core.Infrastructure.Extension;
using Microsoft.EntityFrameworkCore.Storage;
using System.Data;
using System.Threading.Tasks;
using System.Threading;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Cms.Core.Infrastructure.Ui;
using Cms.Core.Infrastructure.Common;
using Cms.Core.Data.Sql;

namespace Cms.Core.Data.UnitOfWork
{
    public class UnitOfWork<TDbContext> : IUnitOfWork where TDbContext : DbContext
    {
        private readonly TDbContext _dbContext;

        private IDbContextTransaction currenTtransaction = null;
        private AsyncLocal<string> asyncLocal = new AsyncLocal<string>();
     

        private readonly ILoggerHelper _loggerHelper;
        //private Dictionary<string, ActiveTransactionInfo> ActiveTransactionInfos { get; }


        public UnitOfWork(TDbContext dbContext)
        {

            _dbContext = dbContext;
            _loggerHelper = ServiceLocator.Instance.GetService<ILoggerHelper>();
            HasCommited = false;
            //ActiveTransactionInfos = new Dictionary<string, ActiveTransactionInfo>();
        }


        public void BeginTransaction()
        {

            currenTtransaction = GetTransaction();
        }

        public void Commit(Action action)
        {
            action.NotNull(nameof(action));
            if (HasCommited)
            {
                return;
            }

            if (currenTtransaction == null)
            {
                
                try
                {
                    BeginTransaction();
                    action?.Invoke();
                    currenTtransaction.Commit();
                }
                catch (Exception e)
                {
                    currenTtransaction.Rollback();
                    _loggerHelper.Error(this, e.Message);
                    HasCommited = true;
                    throw e;
                }
                HasCommited = true;
            }
        }
        public async Task<OperationResult> Commit(Func<Task<OperationResult>> func)
        {
            func.NotNull(nameof(func));
            OperationResult result = new OperationResult();
            if (!HasCommited)
            {
                if (currenTtransaction == null)
                {
                    try
                    {
                        BeginTransaction();
                        result =await func.Invoke();
                        currenTtransaction.Commit();
                        return result;
                    }
                    catch (Exception e)
                    {
                        currenTtransaction.Rollback();
                        _loggerHelper.Error(this, e.Message);
                        HasCommited = true;
                        return new OperationResult()
                        {
                            Type = OperationResultType.Error,
                            Message = e.Message,
                            
                        };
                    }

                }
            }
            HasCommited = true;
            result.Type = OperationResultType.NoChanged;
            result.Message = "操作没有引发任何变化";
            return result;
        }
        public OperationResult Commit(Func<OperationResult> func)
        {
            func.NotNull(nameof(func));
            OperationResult result = new OperationResult();
            if (!HasCommited)
            {
                if (currenTtransaction == null)
                {
                    try
                    {
                        BeginTransaction();
                        result = func?.Invoke();
                        currenTtransaction.Commit();
                        return result;
                    }
                    catch (Exception e)
                    {
                        currenTtransaction.Rollback();
                        _loggerHelper.Error(this, e.Message);
                        HasCommited = true;
                        throw e;
                    }

                }
            }
            HasCommited = true;
            result.Type = OperationResultType.NoChanged;
            result.Message = "操作没有引发任何变化";
            return result;
        }
        public void Commit()
        {

            if (HasCommited)
            {
                return;
            }

            if (currenTtransaction != null)
            {
                try
                {
                    currenTtransaction.Commit();
                }
                catch (Exception e)
                {
                    currenTtransaction.Rollback();
                    _loggerHelper.Error(this,e.Message);
                    HasCommited = true;
                    throw e;
                }
             
            }
            HasCommited = true;


        }

  

        /// <summary>释放对象.</summary>
        public void Dispose()
        {
            if (currenTtransaction.IsNotNull())
            {
                currenTtransaction.Dispose();
            }
        }


        public IDbContextTransaction GetTransaction()
        {
            return this.Database().BeginTransaction();
        }
        public IDbContextTransaction GetTransaction(IsolationLevel isolationLevel)
        {
            return this.Database().BeginTransaction(isolationLevel);
        }

        public async Task<IDbContextTransaction> GetTransactionAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            return await this.Database().BeginTransactionAsync(cancellationToken);
        }
        public async Task<IDbContextTransaction> GetTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken = default(CancellationToken))
        {
            return await this.Database().BeginTransactionAsync(isolationLevel, cancellationToken);
        }

        public DatabaseFacade Database()
        {
            return this.GetContext().Database;
        }


        public DbContext GetContext()
        {


            return _dbContext as DbContext;

        }





        public bool HasCommited { get; private set; }


        /// <summary>
        /// sql查询（简单类型）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public IEnumerable<T> SqlQuery<T>(string sql, Dictionary<string,object>  paraDic) where T : class, new()
        {
            return this.Database().SqlQuery<T>(sql, paraDic);
        }

        /// <summary>
        /// sql查询
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="paraDic"></param>
        /// <returns></returns>

        public IEnumerable<dynamic> SqlQuery(string sql, Dictionary<string, object> paraDic)
        {
            return this.Database().SqlQuery<dynamic>(sql, paraDic);
            
        }

        /// <summary>
        /// 异步sql查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="paraDic"></param>
        /// <returns></returns>
        public async Task<IEnumerable<T>> SqlQueryAsync<T>(string sql, Dictionary<string, object> paraDic) where T : class, new()
        {
            return await this.Database().SqlQueryAsync<T>(sql, paraDic);
        }
    }
}
